昨天提到了 useRef 的一些簡易的使用方式,今天再來更深入一點,來說說 useref 是為了解決什麼問題吧!
import { useState } from "react"
const RenderTime = () => {
const [renderCount, setRenderCount] = useState(0)
useEffect(() => {
setRenderCount(pervCount => pervCount + 1)
})
return (
<div>
<h1>渲染次數: {renderCount} </h1>
</div>
)
}
export { RenderTime }
若是我們使用 useState 去計算畫面渲染的次數的話...
我想聰明的你應該也看出來了,這樣會造成無窮迴圈,因為每次渲染畫面時都會執行 useEffect,進入到 useEffect 又會執行 setRenderCount,這樣又會呼叫 React 再次渲染畫面,就會造成無窮迴圈,這時我們就可以使用 useRef 去紀錄。
因為昨天也提到了使用 useRef 不會渲染畫面,所以我們可以這樣寫
import { useEffect, useState, useRef } from "react"
const RenderTime = () => {
const [renderCount, setRenderCount] = useState(0)
const countRef = useRef(0)
useEffect(() => {
countRef.current += 1
})
return (
<div>
<button onClick={() => setRenderCount(prevCount => prevCount + 1 )}>按我</button>
<h1>渲染次數: {countRef.current} </h1>
</div>
)
}
export { RenderTime }
這樣會畫面只會因為 setRenderCount 而渲染畫面,所以 useEffect 中就只會乖乖的紀錄 countRef.current 的值
昨天我們也提到了,在 React 中我們可能會用on..
系列的事件去綁定元素,但是 useRef 讓我們可以不用讓我們一定要用事件去綁定事件,這樣的效果就很像 原生 JavaScript 的 queryselector
一樣
import { useState, useRef } from "react";
import "./index.css"
const Text = () => {
const [text, setText] = useState("");
const textRef = useRef("")
const textHandler = () => {
setText(textRef.current.value)
}
const inputFocus = () => {
textRef.current.focus()
}
return (
<>
<div>
<input type="text" ref={textRef} />
<div>
目前文字: {text}
</div>
<button className="button" onClick={inputFocus}>按此可以進行輸入</button>
</div>
<div className="button">
<button onClick={textHandler}>送出文字</button>
</div>
</>
)
}
export { Text }
以上面的這個例子,就像是一個表單再填入的時候,我們並不用使用 onChange
事件去監聽,去獲取他每次改變的值,我們只是要獲的 input
最終的值而已,這種情況就很適合使用 useRef
這兩天我們對於 useRef 的了解就是,他是個物件
,其中會有一個 current
的屬性,改變 current
不會造成 re-render,我們都知道了這幾點之後,那就讓我們來看看何謂使用 useRef 去獲取過去的值吧~
import { useState, useRef, useEffect } from "react";
const Past = () => {
const [value, setValue] = useState("")
const pastRef = useRef("")
useEffect(() => {
pastRef.current = value
}, [value])
return (
<>
<div>
<input type="text" ref={pastRef} onChange={(e) => setValue(e.target.value)} />
</div>
<div>
現在的輸入框文字:{ value }
</div>
<div>
紀錄過去吧:{ pastRef.current }
</div>
</>
)
}
export { Past }
有沒有覺得很神奇,為什麼 useRef 可以造成這樣的效果呢?
讓我們看看input
標籤,我們綁定一個 onChange
事件,每次輸入框改變的時候就 setvalue
,這是就會呼叫 React 重新渲染畫面,而重新渲染畫面其實就是重新執行 Past
這個 function,所以也執行了 useEffect,但是但是但是,這時的 value
,並沒有改變他還是上一次的值,只有畫面改變而已
我們可以下面這個例子去驗證這件事
import { useState } from "react";
const Try = () => {
const [count, setCount] = useState(0)
const checkCount = () =>{
setCount(pervCount => pervCount + 1 )
console.log(count);
}
return (
<div>
<button onClick={checkCount}>點我</button>
<h1>{count}</h1>
</div>
)
}
export { Try }
每次點擊的時候將 count
+ 1 ,並同時 console.log(count)
,你會發現畫面變了,可是印出來的值還是點擊前的 count
,因為在點擊時做了兩件事,setCount
以及,印出點擊時的 count
所以才會呈現這樣的效果,
所以我們可以用這樣的效果讓 useRef 做到紀錄過去這種事,
這是因為 React 執行渲染的機制,也是 useState 這個 function 造成的
這個例子在我看來就很像 useRef 在用上帝視角看著這個 function,你可以這樣想像,應該會比較容易理解吧!
今天更進一步介紹了 useRef 還可以怎樣作用,雖然可能不知道會不會實際運用到,但是這幾點都可以讓你跟 useRef 變熟,謝謝大家收看~